package main
import (
	"fmt" 
	_ "unsafe"
)

// go 语言不支持函数重载

//----------------- 递归函数
// 打印斐波那契数列
// n = 1 s = 1
// n = 2 s = 1
// n > 2 s = s(n-1) + s(n-2)
func fib(n int) int {
	if n < 3 {
		return 1
	} else {
		return fib(n-2) + fib(n-1)
	}
}

//----------------- 使用指针交换两个值
func exch( a *int, b*int ) {
	t := *a
	*a = *b
	*b = t
}

//----------------- 返回多个值
func cal(a int ,b int) (int , int ) {
	sum := a + b
	sub := a - b
	return sum,sub
	// return sub,sum // 可以的
}

//-----------------  对函数返回多个值命名
// 在返回类型那里指定返回自值变量
func cal2(a int ,b int) (sum int , sub int ) {
	sum = a + b // 注意这里就不能使用 := 来赋值了,因为在返回值形参中已经定义过该变量了
	sub = a - b
	return
}

//----------------- 定义函数类型
// funVar func(int,int)(int,int)
// funVar 是一个函数类型有两个入参和两个返回值
func myFun( funVar func(int,int)(int,int),a int,b int)(int,int) {
	return funVar(a,b) // 调用传递进来的函数
}

type myFunType func(int, int )(int, int ) // 定义一个自己的函数的类型
func myFun2( funVar myFunType,a int,b int)(int,int) {
	return funVar(a,b) // 调用传递进来的函数
}


//----------------- 可变参数函数
// 可变参数一定要放到形参列表的最后面否则报错
func paramsFunc(i int, args... int) {
	fmt.Println("i = ", i)
	fmt.Println("len(args) = ", len(args))
	fmt.Printf("args type = %T", args) // int[] 数组 args 是一个 slice (切片是一个动态数组)  
// 	i =  10
//  len(args) =  3
//  args type = []int
}

func main() {
	
	ft := fib
	fmt.Printf("ft type = %T\n", ft)//ft type = func(int) int
	fmt.Println(fib(7))// 1,1,2,3,5,8,13
	fmt.Printf("ft(8) = %v\n ", ft(8))//ft(8) = 21

	i := 9
	j := 10
	exch(&i,&j)
	fmt.Println("i = ", i)//i =  10
	fmt.Println("j = ", j)//j =  9

	// res01,res02 := cal(1,2);
	res01,res02 := cal2(1,2);
	fmt.Println("cal(1,2)",res01," ," ,res02 ) // 3 ,-1

	// 函数也是一个类型
	res03,res04 := myFun(cal,10,9)
	fmt.Println("myFun(cal,10,9)",res03," ," ,res04 )//19, 1

	res05,res06 := myFun2(cal,10,9)
	fmt.Println("myFun2(cal,10,9)",res05," ," ,res06 )//19, 1

	// 可变参数
	fmt.Println("paramsFunc(10,1,2,3) ")
	paramsFunc(10,1,2,3)

}